import ctypes
import ctypes.wintypes
import threading

user32 = ctypes.windll.user32
WM_MOUSEMOVE = 0x0200

class POINT(ctypes.Structure):
  _fields_ = [("x", ctypes.c_long), ("y", ctypes.c_long)]

class MSLLHOOKSTRUCT(ctypes.Structure):
  _fields_ = [("pt", POINT), ("mouseData", ctypes.wintypes.DWORD), ("flags", ctypes.wintypes.DWORD), ("time", ctypes.wintypes.DWORD), ("dwExtraInfo", ctypes.c_ulong)]

class MouseXY:
  def __del__(self):
    print ("deleted")
  def __init__(self):
    self.hook_id = None
    self.callback = None
    self.xy = (0,0)
    self.t = threading.Thread(target=self.start_hook)
    self.t.start()
    
  def LowLevelMouseProc(self, nCode, wParam, lParam):
    if nCode == 0:
      if wParam == WM_MOUSEMOVE:
        msllhs = MSLLHOOKSTRUCT.from_address(lParam)
        x = msllhs.pt.x
        y = msllhs.pt.y
        self.xy = (x, y)
    return user32.CallNextHookEx(self.hook_id, nCode, ctypes.wintypes.WPARAM(wParam), ctypes.wintypes.LPARAM(lParam))
  
  def set_callback(self, callback):
    self.callback = callback

  def start_hook(self):
    LRESULT = ctypes.c_long
    MYFUNC = ctypes.CFUNCTYPE(LRESULT, ctypes.c_int, ctypes.wintypes.WPARAM, ctypes.wintypes.LPARAM)
    CFIMCP = MYFUNC(self.LowLevelMouseProc)
    self.hook_id = user32.SetWindowsHookExW(14, CFIMCP, None, 0)
    msg = ctypes.wintypes.MSG()
    while user32.GetMessageW(ctypes.byref(msg), None, 0, 0) != 0:
      user32.TranslateMessage(msg)
      user32.DispatchMessageW(msg)

  def stop_hook(self):
    print()
    if self.hook_id:
      user32.UnhookWindowsHookEx(self.hook_id)
      self.hook_id = None
      